<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<link rel="Stylesheet" type="text/css" href="doc.css" />
<title>Working with EMF Operations</title>
</head>
<body>
<h1><a name="top">Working with EMF Operations</a></h1>
<p>
The <a href="../javadoc/org/eclipse/emf/workspace/IWorkspaceCommandStack.html"><em class="CodeName">IWorkspaceCommandStack</em></a>
executes EMF <em class="CodeName">Command</em>s by wrapping them in
<em class="CodeName">IUndoableOperation</em>s and executing them on its
<em class="CodeName">IOperationHistory</em>.  However, clients are encouraged to use the
<a href="../javadoc/org/eclipse/emf/workspace/AbstractEMFOperation.html"><em class="CodeName">AbstractEMFOperation</em></a>
API, instead, to work directly with the operation history, to take advantage of
such features as undo contexts.
</p>

<blockquote>
	<img src="images/operations.png" alt="EMF Operations API"/><br/>
	<font size="-2">[<a href="images/operations.svg">as SVG</a>]</font>
</blockquote>

<p>
<a href="../javadoc/org/eclipse/emf/workspace/AbstractEMFOperation.html"><em class="CodeName">AbstractEMFOperation</em></a>s
execute themselves within a transaction on their editing domain.  In consequence, they
provide rollback support and automatic undo/redo just as the
<em class="CodeName">RecordingCommand</em> does in the core EMF Transaction API.  To use it,
simply define a subclass that implements the protected <em class="CodeName">doExecute()</em>
method, performing whatever changes are required in the resource set.
</p>
<pre class="Code">
// get the workbench's operation history, which is the default history
//   used by the WorkspaceEditingDomainFactory
IOperationHistory history = workbench.getOperationSupport().<b>getOperationHistory</b>();

TransactionalEditingDomain domain = getEditingDomain();

IUndoableOperation operation = new <b>AbstractEMFOperation</b>(domain,
        "Create Books in Libraries") {
    protected IStatus <b>doExecute</b>(IProgressMonitor monitor,
            Iadaptable info) <b>throws ExecutionException</b> {
        Iterator iter = resource.getAllContents();
        while (iter.hasNext()) {  // changes are determined on-the-fly
            Object next = iter.next();
            if (next instanceof Library) {
                ((Library) next).getBooks().add(
                        EXTLibraryFactory.eINSTANCE.createBook());
            }
        }

        return <b>Status.OK_STATUS</b>;
    }};

operation.<b>addUndoContext</b>(myEditorContext);
history.<b>execute</b>(operation, new NullProgressMonitor(), null);
</pre>

<h2>Transaction Options</h2>

<p>
An <em class="CodeName">AbstractEMFTransaction</em> can be initialized with a map of
<a href="../../../org.eclipse.emf.transaction.doc/references/overview/options.html">transaction options</a>.
These options are then applied to the operation's transaction when it is executed on the
operation history.
</p><p>
As is the case in the core EMF Transaction API, the <em class="CodeName">AbstractEMFOperation</em>'s
implementations of the <em class="CodeName">undo()</em> and <em class="CodeName">redo()</em>
methods use the following options for the transactions created for undoing and redoing its
recorded changes:
</p>
<ul>
  <li><em class="CodeName">OPTION_NO_UNDO</em>:  because we are undoing or redoing an
      operation whose changes we have already recorded (including, in the case of
      <a href="#composites">composite operations</a>, and non-EMF operations), there is
      no need to record anew</li>
  <li><em class="CodeName">OPTION_NO_TRIGGERS</em>:  triggers performed during execution
      were recorded and are automatically undone; any additional changes would be
      inappropriate</li>
  <li><em class="CodeName">OPTION_NO_VALIDATION</em>:  there is no need to validate a
      reversion to a previous state of the data</li>
  <li><em class="CodeName">OPTION_IS_UNDO_REDO_TRANSACTION</em>:  the transaction's changes
      are simply undoing or redoing changes made previously</li>
</ul>

<a name="composites"></a>
<h2>Composite EMF Operations</h2>

<p>
<a href="../javadoc/org/eclipse/emf/workspace/CompositeEMFOperation.html"><em class="CodeName">CompositeEMFOperation</em></a>s
can compose both <em class="CodeName">AbstractEMFOperations</em> (including other composites)
and operations on other domains.  For example, a composite can change objects in an EMF
resource as well as edit parts in a GEF drawing surface and code in Java source files that
are all interrelated.  Undo/redo is fully supported and preserves ordering dependencies
between EMF and non-EMF changes.  Transaction rollback correctly undoes non-EMF changes.
</p><p>
A <em class="CodeName">CompositeEMFOperation</em> can be initialized with a list of child
operations, or they can be appended later.  However, they must all be supplied before the
composite is executed.  Children cannot be added or removed after that time.  The
composite operation's undo context is an aggregate of the contexts of its children.
</p>
<pre class="Code">
IOperationHistory history = workbench.getOperationSupport().getOperationHistory();
TransactionalEditingDomain domain = getEditingDomain();
Library mainBranch = getMainBranch();

CompositeEMFOperation composite = new <b>CompositeEMFOperation</b>(domain,
        "Create Book and EditPart");
        
// some hypothetical AbstractEMFOperation subclass
CreateBookOperation createBook = new CreateBookOperation(domain,
        mainBranch, "Great Expectations");
composite.<b>add</b>(createBook);

// some hypothetical non-EMF operation that visualizes the new book (available in
//   the createBook operation after it has executed) in a GEF viewer
composite.<b>add</b>(new VisualizeBook(viewer, createBook));

history.<b>execute</b>(composite, new NullProgressMonitor(), null);
</pre>
<p>
A <em class="CodeName">CompositeEMFOperation</em>, by default, executes child
<em class="CodeName">AbstractEMFOperation</em>s in
<a href="../../../org.eclipse.emf.transaction.doc/references/overview/nesting.html">nested transactions</a>.
For large nested operation structures, this can induce a lot of overhead that may not
be necessary (depending, in particular, on pre-commit trigger requirements).  The transaction
structure can be optimized by telling the composite not to create a nested transaction for
a child operation unless the child uses different transaction options than the parent, using
the <em class="CodeName">setTransactionNestingEnabled()</em> method (passing
<em class="CodeName">false</em>).  Transaction options specified on child operations obey
the usual rules for option inheritance in transaction nesting.
</p><p>
Finally, it is worth noting that the <em class="CodeName">CompositeEMFOperation</em> class
might be expected to implement the Eclipse <em class="CodeName">ICompositeOperation</em>
interface.  The reason why it does not is that it does not support the
<em class="CodeName">IOperationHistory.openOperation()</em> API.  It is good practice with
EMF Transactions to keep them as short as possible, especially read/write transactions
that block all read access (on other threads) for their duration.  The "open operation"
would concept contradict this by promoting long, open-ended transactions.
</p>

<hr/>

<p>
<a href="https://www.eclipse.org/legal/epl-2.0/">Copyright (c) 2006, 2007 IBM Corporation and others.</a>
</p>
</body>
</html>
